from abc import ABC
from typing import List, Tuple, Optional, Set

from utils.funclib import mustcall, MustCall
from pymodels.utils.Explaintation import LMExplaintation


class BasicPlugin(MustCall):
    def __init__(self):
        self.HIBERNATE = 0
        self.WAKE = 1
        self.mode = self.HIBERNATE

    def get_introduction(self) -> str:
        raise NotImplementedError

    @mustcall
    def hibernate(self):
        """
        用于实现插件的休眠状态。
        一个插件如果涉及大量资源，那么不使用该插件时引入这些资源是极为浪费的。因此引入了休眠态和清醒态。
        在`wake`中请求资源，在`hibernate`中对资源进行释放。
        模型初始处于休眠态。
        :return:
        """
        self.mode = self.HIBERNATE

    @mustcall
    def wake(self):
        self.mode = self.WAKE

    def iswake(self) -> bool:
        return self.mode == self.WAKE


class BasicReaderPlugin(BasicPlugin, ABC):
    def __init__(self):
        """
        插件基类。
        每一个数据源处理插件只需要实现该类，即可提供一个新的Reader。
        发布插件时，文件的命名即为支持的文件类型。即名为'txt.py`的插件支持的文件类型为`.txt'。
        """
        super().__init__()

    def search(self, query: str, k: int):
        raise NotImplementedError

    def readbook(self, bookpath: str):
        raise NotImplementedError

    def get_readfile_name(self):
        raise NotImplementedError

    def support_file_type(self) -> Set[str]:
        """
        返回插件额外支持的其他文件类型。如{".docx", ".doc"}。
        :return:
        """
        return set()


class BasicComprehensionPlugin(BasicPlugin, ABC):
    def __init__(self):
        """
        插件基类。
        每一个阅读理解插件只需要实现该类，即可提供一个新的阅读理解模型。
        用于初始化阅读理解类。插件管理器会分析函数签名和注释（reST），并在模型插件管理界面形成一个配置框，用于管理参数。然后会在项目启动时，
        根据存储的参数初始化阅读理解类，添加到Comprehensioner中。
        """
        super().__init__()

    def inference(self, texts: List[str], question: str, explained: bool = False, **kwargs) \
            -> Tuple[str, Optional[LMExplaintation]]:
        """
        用于推理的方法。
        :param texts: 相关的上下文，用于回答问题。
        :param question: 问题。
        :param explained: 是否返回解释信息。
        :param kwargs: 模型自定义的参数。
        :return: 元组，元素依次是`回答`、`pymodels.utils.Explaintation.LMExplaintation`类。若explained==False，则仅返回`答案`。
        """
        raise NotImplementedError